package mylab.utils.spring;

import lombok.experimental.UtilityClass;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@UtilityClass
public class AspectUtil {


    /**
     * 获取切点所标注方法的参数表
     *
     * @param joinPoint 切点
     * @return 参数表：参数名称与参数值
     */

    public Map<String, Object> getMethodParameters(ProceedingJoinPoint joinPoint) {
        // 通过map封装参数和参数值
        HashMap<String, Object> paramMap = new HashMap<>(8);

        //获取切点所注解的方法
        Method method = getMethod(joinPoint);
        assert method != null;

        //获取方法的参数列表
        ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
        String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);

        //获取方法的参数值列表
        Object[] args = joinPoint.getArgs();

        if (parameterNames == null || args == null) {
            return paramMap;
        }
        assert parameterNames.length == args.length;

        for (int i = 0; i < parameterNames.length; i++) {
            paramMap.put(parameterNames[i], args[i]);
        }
        return paramMap;
    }


    /**
     * 获取切面方法上包含的指定注解
     *
     * @param joinPoint       切点
     * @param annotationClass 注解类的ClassType
     * @param <T>             Annotation
     * @return 注解类
     */
    public <T extends Annotation> T getAnnotation(JoinPoint joinPoint, Class<T> annotationClass) {
        Method method = getMethod(joinPoint);
        assert method != null;
        return method.getAnnotation(annotationClass);
    }


    /**
     * 获取切点所注解的方法
     *
     * @param joinPoint 切点
     * @return 方法
     */
    public Method getMethod(JoinPoint joinPoint) {
        Method method = null;
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //为了防止有重载的现象，还是需要传入参数的类型
            method = joinPoint.getTarget().getClass().getMethod(joinPoint.getSignature().getName(), signature.getParameterTypes());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return method;
    }

}
